package com.rslai.commons.http.tools;

import org.apache.http.FormattedHeader;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.NameValuePair;
import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.cookie.SM;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.impl.cookie.BrowserCompatSpec;
import org.apache.http.impl.cookie.NetscapeDraftHeaderParser;
import org.apache.http.message.ParserCursor;
import org.apache.http.util.CharArrayBuffer;

import java.util.ArrayList;
import java.util.List;

/**
 * Cookie 规范适配（某些浏览器 Cookie 处理有误，所以为了模仿它的行为需要重新处理 Cookie）
 * Created by lrs on 2018/8/6.
 */
public class RequestBrowserCompatSpec extends BrowserCompatSpec {

    /**
     * 构造函数
     */
    public RequestBrowserCompatSpec() {
        super(null);
    }

    /**
     * 构造函数，指定日期模式
     * @param datepatterns 日期模式
     */
    public RequestBrowserCompatSpec(final String[] datepatterns) {
        super(datepatterns);
    }

    @Override
    public List<Cookie> parse(final Header header, final CookieOrigin origin) throws MalformedCookieException {
        if (header == null) {
            throw new IllegalArgumentException("Header may not be null");
        }
        if (origin == null) {
            throw new IllegalArgumentException("Cookie origin may not be null");
        }
        String headerName = header.getName();
        if (!headerName.equalsIgnoreCase(SM.COOKIE)) {
            throw new MalformedCookieException("Unrecognized cookie header '" + header.toString() + "'");
        }

        HeaderElement[] headerElements = header.getElements();
        boolean versioned = false;
        boolean netscape = false;
        for (HeaderElement headerElement : headerElements) {
            if (headerElement.getParameterByName("version") != null) {
                versioned = true;
            }
            if (headerElement.getParameterByName("expires") != null) {
                netscape = true;
            }
        }
        if (netscape || !versioned) {
            // Need to parse the header again, because Netscape style cookies do not correctly
            // support multiple header elements (comma cannot be treated as an element separator)
            NetscapeDraftHeaderParser parser = NetscapeDraftHeaderParser.DEFAULT;
            CharArrayBuffer buffer;
            ParserCursor cursor;
            if (header instanceof FormattedHeader) {
                buffer = ((FormattedHeader) header).getBuffer();
                cursor = new ParserCursor(((FormattedHeader) header).getValuePos(), buffer.length());
            } else {
                String s = header.getValue();
                if (s == null) {
                    throw new MalformedCookieException("Header value is null");
                }
                buffer = new CharArrayBuffer(s.length());
                buffer.append(s);
                cursor = new ParserCursor(0, buffer.length());
            }
            headerElements = new HeaderElement[] { parser.parseHeader(buffer, cursor) };
        }
        return parse(headerElements, origin);
    }

    /**
     * 将 cookie 转为 BasicClientCookie
     * @param elems HeaderElement 数组
     * @param origin CookieOrigin
     * @return cookie 的 list
     * @throws MalformedCookieException MalformedCookieException
     */
    protected List<Cookie> parse(final HeaderElement[] elems, final CookieOrigin origin) throws MalformedCookieException {
        List<Cookie> cookies = new ArrayList<Cookie>(elems.length);
        for (HeaderElement headerelement : elems) {
            String name = headerelement.getName();
            String value = headerelement.getValue();
            if (name == null || name.length() == 0) {
                throw new MalformedCookieException("Cookie name may not be empty");
            }

            BasicClientCookie cookie = new BasicClientCookie(name, value);
            cookie.setPath(getDefaultPath(origin));
            cookie.setDomain(getDefaultDomain(origin));
            cookies.add(cookie);

            // 循环遍历
            NameValuePair[] attribs = headerelement.getParameters();
            for (int j = attribs.length - 1; j >= 0; j--) {
                NameValuePair attrib = attribs[j];
                BasicClientCookie cookie1 = new BasicClientCookie(attrib.getName(), attrib.getValue());
                cookie1.setPath(getDefaultPath(origin));
                cookie1.setDomain(getDefaultDomain(origin));
                cookies.add(cookie1);
            }
        }
        return cookies;
    }
}
